<?php
/**
 * Created by PhpStorm.
 * User: 王柯 <wangke.email@foxmail.com>
 * Date: 2018\4\3 0003
 * Time: 13:06
 */
namespace app\api\controller;

use app\api\model\Account;
use app\api\model\BankAccount;
use app\api\model\LessonComment;
use app\api\model\Order;
use app\api\model\Settlement;
use app\api\model\SettlementRecord;
use think\Controller;
use think\Db;
use app\common\lib\exception\ApiException;
use think\Log;
use think\Cache;
use wxpay\request\WxAppPay;
use alipay\request\AliAppPay;
use alipay\request\AliWapPay;
use alipay\AlipayTradeService;
use app\common\lib\wechat\WxCommon;
class Payment extends Controller{
    /**
     * 阿里wap支付
     * @author 王柯 <wangke.email@foxmail.com>
     * @return void
     */
    public function aliWap(){
        $data = $_POST;
        if (empty($data)) {
            throw new ApiException('数据不合法！',401);
        }

        if (empty($data['body']) && !isset($data['body'])) {
            throw new ApiException('body(交易描述) is not found',404);
        }

        if (empty($data['subject']) && !isset($data['subject'])) {
            throw new ApiException('subject(标题) is not found',404);
        }

        if (empty($data['out_trade_no']) && !isset($data['out_trade_no'])) {
            throw new ApiException('out_trade_no(订单编号) is not found',404);
        }

        if (empty($data['total_amount']) && !isset($data['total_amount'])) {
            throw new ApiException('total_amount(订单金额) is not found',404);
        }

        $m = new AliWapPay();

        //订单有效期10分钟
        $data['timeout_express'] = '10m';

        $m::pay($data);
    }

    /**
     * 支付宝app支付
     * @author 王柯 <wangke.email@foxmail.com>
     * @return void
     */
    public function aliApp(){
        $data = $_POST;
        if (empty($data)) {
            throw new ApiException('数据不合法！',401);
        }

        if (empty($data['body']) && !isset($data['body'])) {
            throw new ApiException('body(交易描述) is not found',404);
        }

        if (empty($data['subject']) && !isset($data['subject'])) {
            throw new ApiException('subject(标题) is not found',404);
        }

        if (empty($data['out_trade_no']) && !isset($data['out_trade_no'])) {
            throw new ApiException('out_trade_no(订单编号) is not found',404);
        }

        if (empty($data['total_amount']) && !isset($data['total_amount'])) {
            throw new ApiException('total_amount(订单金额) is not found',404);
        }

        $m = new AliAppPay();

        //订单有效期10分钟
        $data['timeout_express'] = '10m';

        $orderInfo = $m::pay($data);

        return show(config('code.success'),'ok',$orderInfo);
    }

    /**
     * 阿里交易订单查询
     * @author 王柯 <wangke.email@foxmail.com>
     * @return array|bool|\mix|mixed|\SimpleXMLElement|\stdClass|string|\提交表单HTML文本
     */
    public function aliQuery(){
        $data = $_POST;

        $data['out_trade_no'] = '15240421305149344';

        if (empty($data['out_trade_no']) && !isset($data['out_trade_no']) && empty($data['trade_no']) && !isset($data['trade_no'])) {
            throw new ApiException('out_trade_no(外部订单号) 或者 trade_no(内部订单号) is not found',404);
        }

        $info = \alipay\request\AliQuery::exec($data);
        return $info;
    }

    /**
     * 阿里交易订单关闭
     * @author 王柯 <wangke.email@foxmail.com>
     * @return array|bool|\mix|mixed|\SimpleXMLElement|\stdClass|string|\提交表单HTML文本
     */
    public function aliClose(){
        $data = $_POST;

        $data['out_trade_no'] = '15240466845257937';

        if (empty($data['out_trade_no']) && !isset($data['out_trade_no']) && empty($data['trade_no']) && !isset($data['trade_no'])) {
            throw new ApiException('out_trade_no(外部订单号) 或者 trade_no(内部订单号) is not found',404);
        }

        $info = \alipay\request\AliClose::exec($data);
        return $info;
    }

    /**
     * 微信app支付
     * @author 王柯 <wangke.email@foxmail.com>
     * @return void
     */
    public function wxApp(){
        $response = new WxAppPay();

        /*$data = [
            'body' => '充值',
            'subject' => '充值',
            'out_trade_no' => '12334121asss',
            'total_amount' => 1,
        ];*/

        $data = $_POST;

        if (empty($data)) {
            throw new ApiException('数据不合法！',401);
        }

        if (empty($data['body']) && !isset($data['body'])) {
            throw new ApiException('body(交易描述) is not found',404);
        }

        if (empty($data['subject']) && !isset($data['subject'])) {
            throw new ApiException('subject(标题) is not found',404);
        }

        if (empty($data['out_trade_no']) && !isset($data['out_trade_no'])) {
            throw new ApiException('out_trade_no(订单编号) is not found',404);
        }

        if (empty($data['total_amount']) && !isset($data['total_amount'])) {
            throw new ApiException('total_amount(订单金额) is not found',404);
        }

        $return = $response::pay($data);

        return json($return);
    }

    /**
     * 微信订单查询
     * @param string $data['out_trade_no'] 商户订单号 *必传
     * @author 王柯 <wangke.email@foxmail.com>
     * @return \成功时返回，其他抛异常
     */
    public function wxQuery(){
       $data = $_POST;

       //$data['out_trade_no'] = '1217752501201407033233368018';

                    if (empty($data['out_trade_no']) && !isset($data['out_trade_no'])) {
                        throw new ApiException('out_trade_no(外部订单号)is not found',404);
                    }

                    $info = \wxpay\request\WxQuery::exec($data['out_trade_no']);
                    return $info;
                }

    /**
     * 支付宝异步通知
     * @param int cost_type 费用类型 1学币 2学费 3教师费用 4推荐奖金 5管理费用 6专项费用 7教具费用 8合作费用 9教务费用 10教室费用 11重上费用
     * @param int account_type 流水类型 1充值 2提现 3其他
     * @channel 支付渠道 backstage（后台） ali（支付宝）wx（微信）remain（余额）
     * @author 王柯 <wangke.email@foxmail.com>
     * @return void
     */
    public function AliPayNotify()
    {
        $request = input('param.');

        if(empty($request['sign'])){
            throw new ApiException('参数错误！',401);
        }

        Db::startTrans();

        try{
            $signType = $request['sign_type'];
            $check = new AlipayTradeService();

            //效验签名
            $flag = $check->rsaCheck($request, $signType);

            if($flag){
                //查询订单信息
                $order_sn = Cache::pull('order:'.$request['out_trade_no']);

                //查询充值记录信息
                $account_sn = Cache::pull('account:'.$request['out_trade_no']);

                if($order_sn){
                    //保存支付成功订单信息
                    $order = new Order();

                    //支付状态 0未支付 1已支付
                    $order_sn['pay_status'] = 1;

                    $order->allowField(true)->save($order_sn);

                    $comment = new LessonComment();

                    $commentData = [
                        //评论课程id
                        'lesson_id' => $order_sn['lesson_id'],

                        //评论课程sn
                        'comment_lesson_sn' => $order_sn['order_lesson_sn'],

                        //评论课程时间
                        'comment_time' => time(),

                        //评论等级
                        'comment_rank' => 1,

                        //评论用户id
                        'comment_id' => $order_sn['user_id'],

                        //评论状态 0不评论 1需要评论
                        'comment_status' => 1,

                        //订单id
                        'ord_id' => $order->getLastInsID(),
                    ];

                    //插入相关信息到评论表
                    $comment->allowField(true)->save($commentData);

                    $settlement = new Settlement();

                    //订单id
                    $set['order_id'] = $commentData['ord_id'];

                    //插入相关信息到结算表
                    $settlement->allowField(true)->save($set);

                    //插入相关信息到流水记录表
                    $accounts = new Account();

                    $accounts::addAccount($order_sn['order_sn'],$order_sn['user_id'],$order_sn['cost_description'],-$request['total_amount'],$order_sn['cost_type'],'ali',3,1);

                    //发送消息通知
                    SendMessage($order_sn['user_id'],$order_sn['cost_description'],date('Y-m-d H:i:s').' '.$order_sn['cost_description'].'成功！ 订单号【'.$order_sn['order_sn'].'】');

                    Db::commit();
                    exit('success');
                }elseif($account_sn){
                    $accounts = new Account();

                    //插入相关信息到流水记录表
                    $accounts::addAccount($account_sn['account_sn'],$account_sn['user_id'],$account_sn['cost_description'],$request['total_amount'],$account_sn['cost_type'],'ali',3,1);

                    //发送消息通知
                    SendMessage($account_sn['user_id'],$account_sn['cost_description'],date('Y-m-d H:i:s').' '.$account_sn['cost_description'].'成功！ 订单号【'.$account_sn['account_sn'].'】');

                    //录入充值学费
                    $student = new \app\api\model\Student();

                    if($account_sn['cost_type'] == 1){
                        $coin = $student->getStudentMoneyByStudentId($account_sn['user_id']);
                        $money['coin'] = $coin['coin'] + $request['total_amount'];
                        $student->where('student_id='.$account_sn['user_id'])->update($money);
                    }

                    if($account_sn['cost_type'] == 2){
                        $tuition = $student->getStudentMoneyByStudentId($account_sn['user_id']);
                        $money['tuition'] = $tuition['tuition'] + $request['total_amount'];
                        $student->where('student_id='.$account_sn['user_id'])->update($money);
                    }

                    Db::commit();
                    exit('success');
                }
            } else {
                Log::write('验证签名失败：'.json_encode($request)."\r\n");
                exit('fail');
            }
        }catch(\Exception $e){
            Db::rollback();
            Log::write('支付异常信息：'.$e->getMessage().json_encode($request)."\r\n");
        }
    }

    /**
     * 微信异步通知
     * @param int cost_type 费用类型 1学币 2学费 3教师费用 4推荐奖金 5管理费用 6专项费用 7教具费用 8合作费用 9教务费用 10教室费用 11重上费用
     * @param int account_type 流水类型 1充值 2提现 3其他
     * @channel 支付渠道 backstage（后台） ali（支付宝）wx（微信）remain（余额）
     * @author 王柯 <wangke.email@foxmail.com>
     * @return void
     */
    public function WxPayNotify()
    {
        require_once EXTEND_PATH.'/wxpay/lib/WxPay.Data.php';

        $wxpay = new \WxPayDataBase();
        
        $wx = new WxCommon();

        Db::startTrans();

        try{
            //接收微信返回的数据数据,返回的xml格式
            $xmlData = file_get_contents('php://input');

            //$result = \WxPayResults::Init($xmlData);

            //将xml格式转换为数组
            $data = $wxpay->FromXml($xmlData);

            if($data['sign'] == $wxpay->getSign($data)){
                if ($data['result_code'] == 'SUCCESS'){

                    //查询订单信息
                    $order_sn = Cache::pull('order:'.$data['out_trade_no']);

                    //查询充值记录信息
                    $account_sn = Cache::pull('account:'.$data['out_trade_no']);

                    if($order_sn){
                        //保存支付成功订单信息
                        $order = new Order();

                        //支付状态 0未支付 1已支付
                        $order_sn['pay_status'] = 1;

                        $order->allowField(true)->save($order_sn);

                        $comment = new LessonComment();

                        $commentData = [
                            //评论课程id
                            'lesson_id' => $order_sn['lesson_id'],

                            //评论课程sn
                            'comment_lesson_sn' => $order_sn['order_lesson_sn'],

                            //评论课程时间
                            'comment_time' => time(),

                            //评论等级
                            'comment_rank' => 1,

                            //评论用户id
                            'comment_id' => $order_sn['user_id'],

                            //评论状态 0不评论 1需要评论
                            'comment_status' => 1,

                            //订单id
                            'ord_id' => $order->getLastInsID(),
                        ];

                        //插入相关信息到评论表
                        $comment->allowField(true)->save($commentData);

                        $settlement = new Settlement();

                        //订单id
                        $set['order_id'] = $commentData['ord_id'];

                        //插入相关信息到结算表
                        $settlement->allowField(true)->save($set);

                        //插入相关信息到流水记录表
                        $accounts = new Account();
                        $accounts::addAccount($order_sn['order_sn'],$order_sn['user_id'],$order_sn['cost_description'],$data['total_fee'] / 100,$order_sn['cost_type'],'wx',$order_sn['account_type'],1);

                        //发送消息通知
                        SendMessage($order_sn['user_id'],$order_sn['cost_description'],date('Y-m-d H:i:s').' '.$order_sn['cost_description'].'成功！ 订单号【'.$order_sn['order_sn'].'】');

                    }elseif($account_sn){
                        $accounts = new Account();

                        //插入相关信息到流水记录表
                        $accounts::addAccount($account_sn['account_sn'],$account_sn['user_id'],$account_sn['cost_description'],$data['total_fee'] / 100,$account_sn['cost_type'],'wx',$account_sn['account_type'],1);

                        //发送消息通知
                        SendMessage($account_sn['user_id'],$account_sn['cost_description'],date('Y-m-d H:i:s').' '.$account_sn['cost_description'].'成功！ 订单号【'.$account_sn['account_sn'].'】');

                        //录入充值学费
                        $student = new \app\api\model\Student();

                        if($account_sn['cost_type'] == 1){
                            $coin = $student->getStudentMoneyByStudentId($account_sn['user_id']);
                            $money['coin'] = $coin['coin'] + $data['total_fee'] / 100;
                            $student->where('student_id='.$account_sn['user_id'])->update($money);
                        }

                        if($account_sn['cost_type'] == 2){
                            $tuition = $student->getStudentMoneyByStudentId($account_sn['user_id']);
                            $money['tuition'] = $tuition['tuition'] + $data['total_fee'] / 100;
                            $student->where('student_id='.$account_sn['user_id'])->update($money);
                        }
                    }

                    Db::commit();

                    $return['return_code'] = 'SUCCESS';
                    $return['return_msg'] = 'OK';
                    $string = $wx::arrayToXml($return);

                    echo $string; exit;
                }else{
                    Log::write("支付失败信息：".json_encode($data).date("Y-m-d H:i:s"),time()."\r\n");
                }
            }else{
                Log::write("签名验证失败：".json_encode($data).date("Y-m-d H:i:s"),time()."\r\n");
            }
        }catch (\Exception $e){
            Db::rollback();
            Log::write($e->getMessage()."\r\n"."支付异常信息：".json_encode($data).date("Y-m-d H:i:s"),time()."\r\n");
        }
    }

    /**
     * 绑定银行卡
     * @param int user_id 用户id *必传
     * @param string bank_tel 银行绑定手机号码 *必传
     * @param string bank_full_name 银行开户姓名 *必传
     * @param string bank_card 银行卡号 *必传
     * @param string id_card 开户身份证号码 *必传
     * @param string bank_name 银行名称（如：建设银行） *必传
     * @author 王柯 <wangke.email@foxmail.com>
     * @return array|string|\think\response\Json
     */
    public function bindingBank(){
        $data = $_POST;

        /*$data['bank_tel'] = '18275185832';
        $data['bank_full_name'] = '王柯';
        $data['bank_card'] = '6217003810062587293';
        $data['id_card'] = '511621199308118213';
        $data['bank_name'] = '建设银行1';
        //用户id
        $data['user_id'] = 1;*/

        $wx = new WxCommon();
        
        //获取银行编号
        $data['bank_code'] = $wx::getBankCode($data['bank_name']);

        if(empty($data['bank_code'])){
            return show(config('code.error'),'该银行平台不支持！');
        }

        //效验绑定银行卡
        $check = db('bank_account')->where("user_id='".$data['user_id']."' AND bank_card='".$data['bank_card']."'")->find();

        if(!empty($check)){
            return show(config('code.error'),'你已经绑定过该银行卡！');
        }

        //是否返回银行信息 YES NO 可选参数
        $request['ReturnBankInfo'] = 'YES';

        //银行卡号
        $request['cardNo'] = $data['bank_card'];

        //身份证号码
        $request['idNo'] = $data['id_card'];

        //开户名
        $request['name'] = $data['bank_full_name'];

        //手机号
        $request['phoneNo'] = $data['bank_tel'];

        //按字典排序
        ksort($request);

        //发送请求
        $host = "https://yunyidata.market.alicloudapi.com";
        $path = "/bankAuthenticate4";
        $method = "POST";
        $appcode = config('code.app_code');
        $headers = array();
        array_push($headers, "Authorization:APPCODE " . $appcode);
        //根据API的要求，定义相对应的Content-Type
        array_push($headers, "Content-Type".":"."application/x-www-form-urlencoded; charset=UTF-8");
        $bodys = http_build_query($request);
        $url = $host . $path;
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($curl, CURLOPT_FAILONERROR, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_HEADER, true);
        if (1 == strpos("$".$host, "https://"))
        {
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        }
        curl_setopt($curl, CURLOPT_POSTFIELDS, $bodys);
        $result = curl_exec($curl);
        curl_close($curl);
        preg_match("/{.+}/", $result,$result);
        $result = json_decode($result[0],true);

        if($result['respCode'] == '0000'){
            $bankData = [
                'user_id' => $data['user_id'],
                'bank_full_name' => $result['name'],
                'bank_card' => $result['cardNo'],
                'id_card' => $result['idNo'],
                'bank_tel' => $result['phoneNo'],
                'bank_name' => $data['bank_name'],
                'bank_code' => $data['bank_code'],
                'bank_type' => $result['bankType'],
            ];

            try{
                $m = new BankAccount();

                $save = $m::create($bankData);

                if($save){
                    return show(config('code.success'),'绑定银行卡成功！');
                }else{
                    return show(config('code.error'),'绑定银行卡失败！');
                }
            }catch(\Exception $e){
                Log::write($e->getMessage());
                throw new ApiException($e->getMessage(),500);
            }
        }else{
            return show(config('code.error'),'绑定银行卡失败！你输入的信息有误！');
        }
    }

    /**
     * 用户提现到银行卡
     * @param int user_id 用户id *必传
     * @param int total_amount 提现金额（单位：分） *必传
     * @author 王柯 <wangke.email@foxmail.com>
     * @return array|string|\think\response\Json
     */
    public function wxWithdrawals(){
        $request = $_POST;

        $wx = new WxCommon();

        /*$request['user_id'] = 1;
        $request['bank_full_name'] = '王柯';
        $request['bank_code'] = '1003';
        $request['bank_card'] = '6217003810062587293';
        $request['total_amount'] = 2;*/

        if(!isset($request['user_id'])){
            throw new ApiException('user_id（用户id） is not found！',404);
        }

        if(!isset($request['bank_account_id'])){
            throw new ApiException('bank_account_id（银行账户id） is not found！',404);
        }

        if(!isset($request['total_amount'])){
            throw new ApiException('total_amount（提现金额） is not found！',404);
        }

        if($request['total_amount'] < 1 || $request['total_amount'] > 5000000){
            return show(config('code.error'),'单笔提现必须大于等于0.01元且小于等于5万元！');
        }

        //用户银行账户信息
        $bank_account_info = db('bank_account')->where('user_id='.$request['user_id'].' AND id='.$request['bank_account_id'])->find();

        $request['bank_card'] = $bank_account_info['bank_card'];
        $request['bank_full_name'] = $bank_account_info['bank_full_name'];
        $request['bank_code'] = $bank_account_info['bank_code'];

        //用户可提现余额
        $user_info = db('user')->where('id='.$request['user_id'])->field('rec_bonus')->find();

        //提现手续费
        $service_cost = $wx::wxWithdrawalsServiceCost($request['total_amount']);

        if($request['total_amount'] / 100 > $user_info['rec_bonus']){
            return show(config('code.error'),'输入的金额不正确！');
        }elseif(($user_info['rec_bonus'] - $request['total_amount'] / 100) < $service_cost / 100){
            return show(config('code.error'),'剩余余额不足以支付手续费 ¥ '.($service_cost / 100).',当前最大可提现金额为 ¥ '.(($user_info['rec_bonus'] - $wx::wxWithdrawalsServiceCost($user_info['rec_bonus'] * 100) / 100) < 0 ? 0 : ($user_info['rec_bonus'] - $wx::wxWithdrawalsServiceCost($user_info['rec_bonus'] * 100) / 100)),['total_amount' => ($user_info['rec_bonus'] - $wx::wxWithdrawalsServiceCost($user_info['rec_bonus'] * 100) / 100) < 0 ? 0 : ($user_info['rec_bonus'] - $wx::wxWithdrawalsServiceCost($user_info['rec_bonus'] * 100) / 100),'service_cost' => $service_cost],'10000');
        }

        //提现金额正确返回
        $return = [
            //当前提现金额
            'total_amount' => $request['total_amount'],

            //提示信息
            'service_cost' => $service_cost,
        ];

        //支付密码
        $pay_password = db('user')->where('id='.$request['user_id'])->field('pay_password')->find();

        if(empty($request['pay_password'])){
            return show(config('code.error'), '你还未输入支付密码！',$return,'10001');
        }

        if(md5($request['pay_password']) != $pay_password['pay_password']){
            return show(config('code.error'), '支付密码不正确！');
        }

        //生成流水号
        $request['account_sn'] = date('YmdHis').rand(1000,9999);

        //微信提现统一入口返回信息
        $array = \wxpay\request\WxWithdrawals::query($request);

        //提现判断
        if($array['return_code'] == 'SUCCESS'){

            if($array['result_code'] == 'FAIL'){

                return show(config('code.error'),$array['return_msg'].'！'.$array['err_code_des']);
            }else{

                $m = new Account();

                //插入相关信息到流水记录表
                $m::addAccount($request['account_sn'],$request['user_id'],'推荐奖金提现',-$array['amount'] / 100,4,'wx',2,1);

                Db::startTrans();

                try{

                    $money['rec_bonus'] = $user_info['rec_bonus'] - $service_cost - $array['amount'] / 100;

                    $save = db('user')->where('id='.$request['user_id'])->update($money);

                    if($save){

                        //发送消息通知
                        SendMessage($request['user_id'],'申请提现',date('Y-m-d H:i:s').' 你的提现以及受理成功！订单号【'.$request['account_sn'].'】请留意银行账户或者在我的流水记录查询到账详情！提现手续费 '.($array['cmms_amt']/100).' 元');

                        Db::commit();

                        return show(config('code.success'),'申请提现成功！');
                    }else{
                        return show(config('code.error'),'申请提现失败！');
                    }
                }catch(\Exception $e){

                    Log::write($e->getMessage()."\r\n".json_encode($array));
                    Db::rollback();
                    throw new ApiException($e->getMessage(),500);
                }
            }
        }else{
            return show(config('code.error',$array['return_msg']));
        }
    }

    /**
     * 查询提现记录
     * @param string order_sn 订单订单流水号 *必传
     * @author 王柯 <wangke.email@foxmail.com>
     * @return array|string|\think\response\Json
     */
    public function wxWithdrawalsQuery(){
        $request = $_POST;

        //查询订单流水号 201804271709076836  201804271709076836
        //$request['order_sn'] = '201804271709076836';

        if(!isset($request['order_sn'])){
            throw new ApiException('请输入提现流水号！',404);
        }

        //微信提现查询统一入口返回信息
        $array = \wxpay\request\WxWithdrawalsQuery::exec($request);

        //判断订单信息
        if($array['result_code'] == 'SUCCESS'){
            if($array['status'] == 'SUCCESS'){
                $return = [
                    'partner_trade_no' => $array['partner_trade_no'],
                    'amount' => $array['amount'] / 100,
                    'create_time' => $array['create_time'],
                    'pay_succ_time' => $array['pay_succ_time'],
                    'cmms_amt' => $array['cmms_amt'],
                ];
                return show(config('code.success'),'提现到账成功！',$return);
            }elseif($array['status'] == 'PROCESSING'){
                return show(config('code.error'),'银行处理中！');
            }else{
                Log::write(json_encode($array));
                return show(config('code.error'),'未知错误！');
            }
        }else{
            return show(config('code.error'),$array['return_msg']);
        }
    }
}
